package io.github.hayeka.a1_threadlocalandmultidatasource.code.datasource;

//==================================
//      @Author hayeka
//      @Email hayeka@2980.com
//      @Date 2021/6/16
//==================================

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.github.hayeka.a1_threadlocalandmultidatasource.code.domain.Tenant;
import io.github.hayeka.a1_threadlocalandmultidatasource.code.holder.TenantHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component("TenantDataSource")
public class TenantDataSource extends AbstractRoutingDataSource {

    private static DataSource defaultDataSource = null;

    static {
        HikariConfig config = new HikariConfig();
        config.setPassword("1234");
        config.setUsername("root");
        config.setDriverClassName("com.mysql.cj.jdbc.Driver");
        config.setJdbcUrl("jdbc:mysql://localhost:3306/defaultDB?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
        defaultDataSource = new HikariDataSource(config);
    }

    private static final Logger log = LoggerFactory.getLogger(TenantDataSource.class);

    private static Map<Object, Object> codeDataSourceMap = new HashMap<>();


    @Override
    public void afterPropertiesSet() {
        initTenant();
    }


    private void initTenant() {
        //去查租户信息
        JdbcTemplate jdbcTemplate = new JdbcTemplate(defaultDataSource);
        List<Map<String, Object>> list =
                jdbcTemplate.queryForList("select tenant_name, tenant_code, db_url, db_user, db_password, tenant_introduce from t_tenant;");

        Tenant tenant = null;
        for (Map<String, Object> map : list) {
            tenant = new Tenant();
            tenant.setTenantName((String) map.get("tenant_name"));
            tenant.setTenantCode((String) map.get("tenant_code"));
            tenant.setDbUrl((String) map.get("db_url"));
            tenant.setDbUser((String) map.get("db_user"));
            tenant.setDbPassword((String) map.get("db_password"));
            tenant.setTenanIntroduce((String) map.get("tenant_introduce"));
            //创建租户的数据源
            DataSource tenantDataSource = createDataSourceByTenant(tenant);
            tenant.setDataSource(createDataSourceByTenant(tenant));
            //放到容器中
            codeDataSourceMap.put(tenant.getTenantCode(), tenantDataSource);
            TenantHolder.initTenant(tenant);
        }
    }

    @Override
    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
        super.setTargetDataSources(codeDataSourceMap);
    }

    @Override
    protected DataSource determineTargetDataSource() {
        if (null == determineCurrentLookupKey()) {
            return defaultDataSource;
        }
        DataSource dataSource = (DataSource) codeDataSourceMap.get(determineCurrentLookupKey());
        log.info("线程:[{}],取了[{}]=>这个数据源", Thread.currentThread().getName(), dataSource);
        return dataSource;
    }

    @Override
    protected Object determineCurrentLookupKey() {
        if (null == TenantHolder.getTenant()) {
            return null;
        }
        return TenantHolder.getTenant().getTenantCode();
    }




    @Override
    public Connection getConnection() throws SQLException {
        Connection connection = super.getConnection();
        log.info("线程:[{}],取了[{}]=>这个Connection", Thread.currentThread().getName(), connection);
        return connection;
    }

    /**
     * 根据租户创建数据源
     *
     * @param tenant
     * @return
     */
    private DataSource createDataSourceByTenant(Tenant tenant) {
        HikariConfig config = new HikariConfig();
        config.setPoolName(tenant.getTenantName() + "定制=>DataSource");
        config.setPassword(tenant.getDbPassword());
        config.setUsername(tenant.getDbUser());
        config.setDriverClassName("com.mysql.cj.jdbc.Driver");
        config.setJdbcUrl(tenant.getDbUrl());
        return new HikariDataSource(config);
    }

}
